suite("notifier", function () {
    "use strict";

    var Notifier = require("./notifier");
    var assert = require("assert");
    var defineType = require("./define-type");

    test("trigger change", function () {
        var Type = defineType(new Notifier, {
            a: undefined
        });

        var instance = new Type;
        instance.a = 0;

        var called = false;
        instance.on("change", function (e) {
            assert(e.target === instance);
            assert(e.property === "a");
            assert(e.oldValue === 0);
            assert(e.newValue === 1);
            called = true;
        });

        instance.a = 1;
        assert(called);
    });

    test("channeling change of properties", function () {
        var Type = defineType(new Notifier, {
            a: undefined
        });

        var instance = new Type;
        instance.a = new Type;
        instance.a.a = 0;

        var called = false;
        instance.on("change", function (e) {
            assert(e.target === instance);
            assert(e.property === "a.a");
            assert(e.oldValue === 0);
            assert(e.newValue === 1);
            called = true;
        });

        instance.a.a = 1;
        assert(called);
    });

    test("unsubscribing of property changes", function () {
        var Type = defineType(new Notifier, {
            a: undefined
        });

        var instance0 = new Type;
        var instance1 = new Type;
        instance1.a = 0;
        instance0.a = instance1;
        instance0.a = null;

        instance0.on("change", function () {
            assert(false);
        });

        instance1.a = 1;
    });

    test("circular references", function () {
        var Type = defineType(new Notifier, {
            t: null
        });

        var a = new Type;
        var b = new Type;
        a.t = b;

        try {
            b.t = a;
            assert(false);
        } catch (error) {
            assert(error.message.indexOf("circular") >= 0);
        }
    });

    test("don't notify when frozen", function () {
        var Type = defineType(new Notifier, {
            p: 1
        });

        var n = new Type;
        n.on("change", function () {
            assert(false);
        });

        n.freeze(true);
        n.p = 2;
    });

    test("triggers all events after unfrozen", function (done) {
        var Type = defineType(new Notifier, {
            p: 1,
            n: null
        });

        var n = new Type;
        n.n = new Type;

        var called = false;
        n.on("change", function (e) {
            assert(e.property === "n.p");
            called = true;
            done();
        });

        n.freeze(true);
        n.n.p = 2;
        n.freeze(false);

        setTimeout(function () {
            if (!called) {
                assert(false, "not triggered this one");
            }
        }, 30);
    });

    test("don't notify on frozen change or frozenEvents", function (done) {
        var Type = defineType(new Notifier, {
            p: 1
        });

        var n = new Type;
        n.on("change", function () {
            assert(false);
        });

        n.frozen = true;
        n.frozen = false;
        n.frozenEvents = [];

        setTimeout(function () {
            done();
        }, 30);
    });
});
